#include "VideoCapture.h"
#include "Manager.h"

void MyOnCaptureFrame(uint32_t id, uint32_t width, uint32_t height,
					  const uint8_t* const slice[], uint64_t timestamp, void* user)
{
	CVideoCapture *pMan = (CVideoCapture *)user;

	if (pMan)
		pMan->OnVideoDataNotfiy(id, width, height, slice, timestamp);
}

CVideoCapture::CVideoCapture(VideoCaptrueDataNotify *pNotify)
: m_pNotify(pNotify)
, m_handle(-1)
, m_ulPlayWnd(0)
, m_nSrcWidth(1280)
, m_nSrcHeight(720)
, m_pBmp(NULL)
, m_bDispaly(false)
{
	//m_pOutFile = fopen("d:\\decode.pcm", "wb");
}

CVideoCapture::~CVideoCapture(void)
{
}

void CVideoCapture::SetDisplayWindow(unsigned long ulPlayWnd)
{
	m_ulPlayWnd = ulPlayWnd;

	RECT rc;
	GetClientRect((HWND)m_ulPlayWnd, &rc);

	m_nDspWidth = rc.right - rc.left;
	m_nDspHeight = rc.bottom - rc.top;

	char sdl[128] = {0};
	sprintf_s(sdl, "SDL_WINDOWID=0x%lx", m_ulPlayWnd);
	SDL_putenv(sdl);

	SDL_Init(SDL_INIT_VIDEO);

	m_pScreen = SDL_SetVideoMode(m_nDspWidth, m_nDspHeight, 32, SDL_SWSURFACE|SDL_ANYFORMAT);

	//SDL_ShowCursor(0);	
}

void CVideoCapture::SetDisplay(bool bIsDisplay)
{
	m_bDispaly = bIsDisplay;
}

int CVideoCapture::InitVideoCapture(void)
{
	m_handle = CreateVideoCaptureHandle(MyOnCaptureFrame, this);

	int nNum = GetNumOfDevices(m_handle);

	if (nNum > 0)
	{
		for (int i = 0; i < nNum; i++)
		{
			DeviceInfo deviceInfo = {0};

			deviceInfo.nIndex = i;

			if (GetDeviceName(m_handle, i, deviceInfo.szDeviceName, MAX_DEVICENAME_LEN, deviceInfo.szUniqueName, MAX_DEVICEUNIQUEID_LEN) == 0)
			{
				GetDeviceCaps(deviceInfo.szUniqueName, deviceInfo.vecCapability);

				m_vecDeviceInfo.push_back(deviceInfo);
			}
		}
	}

	return nNum;
}

int CVideoCapture::UpdateVideoCaptureDevice(void)
{
	int nNum = GetNumOfDevices(m_handle);

	m_vecDeviceInfo.clear();

	if (nNum > 0)
	{
		for (int i = 0; i < nNum; i++)
		{
			DeviceInfo deviceInfo = {0};

			deviceInfo.nIndex = i;

			if (GetDeviceName(m_handle, i, deviceInfo.szDeviceName, MAX_DEVICENAME_LEN, deviceInfo.szUniqueName, MAX_DEVICEUNIQUEID_LEN) == 0)
			{
				GetDeviceCaps(deviceInfo.szUniqueName, deviceInfo.vecCapability);

				m_vecDeviceInfo.push_back(deviceInfo);
			}
		}
	}

	return nNum;
}

int CVideoCapture::GetDeviceList(std::vector<DeviceInfo> &vecDevice)
{
	int nRet = -1;

	if (m_vecDeviceInfo.size() > 0)
	{
		vecDevice = m_vecDeviceInfo;

		nRet = m_vecDeviceInfo.size();
	}	

	return nRet;
}

int CVideoCapture::StartDevCapture(int nIndex, int nWidth, int nHeigth, int nFrameRate)
{
	int nRet = -1;	

	for (int i = 0; i < (int)m_vecDeviceInfo.size(); i++)
	{
		DeviceInfo &devInfo = m_vecDeviceInfo[i];

		if (devInfo.nIndex == nIndex)
		{
			CaptureCapability capability;
			capability.width = nWidth;
			capability.height = nHeigth;
			capability.frameRate = nFrameRate;

			m_nSrcWidth = nWidth;
			m_nSrcHeight = nHeigth;

			if (m_pBmp)
			{
				SDL_FreeYUVOverlay(m_pBmp);
				m_pBmp = NULL;
			}

			m_pBmp = SDL_CreateYUVOverlay(m_nSrcWidth, m_nSrcHeight, SDL_YV12_OVERLAY, m_pScreen);

			nRet = StartCapture(m_handle, nIndex, devInfo.szUniqueName, capability);

			m_bDispaly = true;
			break;
		}
	}

	return nRet;
}

int CVideoCapture::StartDevCaptureEx(const char *pUIDName, int nWidth, int nHeigth, int nFrameRate)
{
	int nRet = -1;	

	char szMsg[1024] = {0};
	sprintf_s(szMsg, "CVideoCapture::StartDevCaptureEx %s %d %d %d \n",pUIDName, nWidth, nHeigth, nFrameRate);
	OutputDebugString(szMsg);

	for (int i = 0; i < (int)m_vecDeviceInfo.size(); i++)
	{
		DeviceInfo &devInfo = m_vecDeviceInfo[i];

		if (strcmp(pUIDName, devInfo.szUniqueName) == 0)
		{
			CaptureCapability capability;
			capability.width = nWidth;
			capability.height = nHeigth;
			capability.frameRate = nFrameRate;

			m_nSrcWidth = nWidth;
			m_nSrcHeight = nHeigth;

			if (m_pBmp)
			{
				SDL_FreeYUVOverlay(m_pBmp);
				m_pBmp = NULL;
			}

			m_pBmp = SDL_CreateYUVOverlay(m_nSrcWidth, m_nSrcHeight, SDL_YV12_OVERLAY, m_pScreen);

			nRet = StartCapture(m_handle, devInfo.nIndex, devInfo.szUniqueName, capability);

			m_bDispaly = true;
			break;
		}
		/*else
		{
			char szMsg[1024] = {0};
			sprintf_s(szMsg, "CVideoCapture::StartDevCaptureEx %s %s \n",pUIDName, devInfo.szUniqueName);
			OutputDebugString(szMsg);
		}*/
	}

	return nRet;
}

int CVideoCapture::StopDevCapture(int nIndex)
{
	int nRet = -1;

	nRet = StopCapture(m_handle, nIndex);

	return nRet;
}

void CVideoCapture::OnVideoDataNotfiy(uint32_t id, uint32_t width, uint32_t height,
					   const uint8_t* const slice[], uint64_t timestamp)
{
	if (m_bDispaly)
		DisplayVideo(slice);

	if (m_pNotify)
		m_pNotify->OnCaptureData(id, slice, width, height, timestamp);
}

void CVideoCapture::DisplaySetDialogBox(const char* pUIDName,
							  const char* dialogTitle, void* parentWindow, uint32_t positionX, uint32_t positionY)
{
	DisplayCaptureSettingsDialogBox(m_handle, pUIDName, dialogTitle, parentWindow, positionX, positionY);
}

void CVideoCapture::DisplaySetDialogBoxEx(int nIndex,
						   const char* dialogTitle, void* parentWindow, uint32_t positionX, uint32_t positionY)
{
	for (int i = 0; i < (int)m_vecDeviceInfo.size(); i++)
	{
		DeviceInfo &devInfo = m_vecDeviceInfo[i];

		if (devInfo.nIndex == nIndex)
		{
			DisplayCaptureSettingsDialogBox(m_handle, devInfo.szUniqueName, dialogTitle, parentWindow, positionX, positionY);

			break;
		}
	}
}

int CVideoCapture::GetDeviceCaps(const char *pDeviceUnique, vector<CaptureCapability> &vecCapability)
{
	int nNum= GetNumOfCapabilities(m_handle, pDeviceUnique);
	for (int i = 0; i < nNum; i++)
	{		
		CaptureCapability capability;
		if (GetCapability(m_handle, pDeviceUnique, i, capability) == 0)
		{
			vecCapability.push_back(capability);
		}
	}

	return nNum;
}

int CVideoCapture::GetDeviceIndex(const char *pDeviceUnique)
{
	for (int i = 0; i < (int)m_vecDeviceInfo.size(); i++)
	{
		if (strcmp(pDeviceUnique, m_vecDeviceInfo[i].szUniqueName) == 0)
			return m_vecDeviceInfo[i].nIndex;
	}

	return -1;
}

int CVideoCapture::DisplayVideo(const uint8_t* const slice[])
{	
	RECT rc;
	GetClientRect((HWND)m_ulPlayWnd, &rc);

	int nWidth = rc.right - rc.left;
	int nHeight = rc.bottom - rc.top;

	if (nWidth != m_nDspWidth || nHeight != m_nDspHeight)
	{
		m_nDspWidth = nWidth;
		m_nDspHeight = nHeight;

		SDL_SetVideoMode(m_nDspWidth, m_nDspHeight, 32, SDL_SWSURFACE|SDL_ANYFORMAT);
	}

	SDL_LockYUVOverlay(m_pBmp);

	memcpy(m_pBmp->pixels[0], slice[0], m_nSrcWidth * m_nSrcHeight);
	memcpy(m_pBmp->pixels[2], slice[1], m_nSrcWidth * m_nSrcHeight/4);
	memcpy(m_pBmp->pixels[1], slice[2], m_nSrcWidth * m_nSrcHeight/4);

	SDL_UnlockYUVOverlay(m_pBmp);

	SDL_Rect rect;

	rect.x = 0;
	rect.y = 0;
	rect.w = m_nDspWidth;
	rect.h = m_nDspHeight;

	SDL_DisplayYUVOverlay(m_pBmp, &rect);
	
	return 0;
}
